//=== EmualtorCodeGenerator.h - Class definition for the EmualtorJIT -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface between the emulator interpreter and jit.
//
//===----------------------------------------------------------------------===//

#include "EmulatorCodeGenerator.h"
#include <cassert>  // for assert.

namespace llvm {

void *
EmulatorCodeGenerator::generateJITEntryTrampoline(uint8_t *StartAddr) 
{
  // Dynamically generated the code snippet that saves the states of the
  // interpreter, only need to save callee-saved registers.
  enterJIT = StartAddr;
  uint8_t *CurrAddr = StartAddr;

#if 0
  *(CurrAddr ++) = 0x53;
  *(CurrAddr ++) = 0x55;

  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x54;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x55;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x56;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x57;
#endif

  *(CurrAddr ++) = 0x50;
  *(CurrAddr ++) = 0x51;
  *(CurrAddr ++) = 0x52;
  *(CurrAddr ++) = 0x53;
  *(CurrAddr ++) = 0x54;
  *(CurrAddr ++) = 0x55;
  *(CurrAddr ++) = 0x56;
  *(CurrAddr ++) = 0x57;

  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x50;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x51;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x52;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x53;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x54;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x55;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x56;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x57;


  *(CurrAddr ++) = 0x48;
  *(CurrAddr ++) = 0x81;
  *(CurrAddr ++) = 0xc4;
  *(CurrAddr ++) = 0x78;
  *(CurrAddr ++) = 0xfb;
  *(CurrAddr ++) = 0xff;
  *(CurrAddr ++) = 0xff;


  // Call to the designated trace.
  *(CurrAddr ++) = 0xFF;
  *(CurrAddr ++) = 0xE6;

  return CurrAddr;
}

void *
EmulatorCodeGenerator::generateJITExitTrampoline(uint8_t *StartAddr) 
{
  // Dynamically generated the code snippet that restores the states of the
  // interpreter. only need to restore callee-saved registers.
  exitJIT = StartAddr;
  uint8_t *CurrAddr = StartAddr;

  *(CurrAddr ++) = 0x48;
  *(CurrAddr ++) = 0x81;
  *(CurrAddr ++) = 0xc4;
  *(CurrAddr ++) = 0x88;
  *(CurrAddr ++) = 0x04;
  *(CurrAddr ++) = 0x00;
  *(CurrAddr ++) = 0x00;

#if 0
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5f;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5e;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5d;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5c;

  *(CurrAddr ++) = 0x5d;
  *(CurrAddr ++) = 0x5b;
#endif
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5f;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5e;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5d;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5c;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5b;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x5a;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x59;
  *(CurrAddr ++) = 0x41;
  *(CurrAddr ++) = 0x58;

  *(CurrAddr ++) = 0x5f;
  *(CurrAddr ++) = 0x5e;
  *(CurrAddr ++) = 0x5d;
  *(CurrAddr ++) = 0x5c;
  *(CurrAddr ++) = 0x5b;
  *(CurrAddr ++) = 0x5a;
  *(CurrAddr ++) = 0x59;
  *(CurrAddr ++) = 0x58;

  // Ret.
  *(CurrAddr ++) = 0xC3;

  return CurrAddr;
}

void *
EmulatorCodeGenerator::generateJITLinkStubExit(uint8_t *StartAddr) 
{
  // Dynamically generated the code snippet that restores the states of the
  // interpreter. only need to restore callee-saved registers.
  linkStubJIT = StartAddr;
  uint8_t *CurrAddr = StartAddr;

  *(CurrAddr ++) = 0x48;
  *(CurrAddr ++) = 0x89;
  *(CurrAddr ++) = 0xe6;

  *(CurrAddr ++) = 0x48;
  *(CurrAddr ++) = 0x8b;
  *(CurrAddr ++) = 0x06;

  *(CurrAddr ++) = 0x48;
  *(CurrAddr ++) = 0x83;
  *(CurrAddr ++) = 0xE8;
  *(CurrAddr ++) = 0x0C;

  *(CurrAddr ++) = 0xC3;

  return CurrAddr;
}

void *
EmulatorCodeGenerator::generateJITDummy(uint8_t *StartAddr) 
{
  // Dynamically generated the code snippet that restores the states of the
  // interpreter. only need to restore callee-saved registers.
  dummyJIT = StartAddr;
  uint8_t *CurrAddr = StartAddr;

  *(CurrAddr ++) = 0xC3;
  return CurrAddr;
}

void EmulatorCodeGenerator::initialize(void* ExecMem, uint32_t Size) 
{
  assert(!initialized && "Try to initialize the EmulatorCodeGenerator more than once");

  void *NewExecMem = ExecMem;
  // JIT enter and exit routines.
  ExecMem = generateJITEntryTrampoline((uint8_t*) ExecMem); 
  ExecMem = generateJITExitTrampoline((uint8_t*) ExecMem); 
  ExecMem = generateJITLinkStubExit((uint8_t*) ExecMem);
  ExecMem = generateJITDummy((uint8_t*) ExecMem);

  assert((uint8_t*)NewExecMem - (uint8_t*)ExecMem - Size < 0 && "Exectuable Memory Overflown");
} 

} // end llvm namespace;
